package com.skd.ssh.dao.base.impl;

import com.skd.ssh.web.query.BaseQuery;
import com.skd.ssh.web.query.PageResult;
import com.skd.ssh.dao.base.BaseDao;
import org.hibernate.Query;
import org.hibernate.Session;
import org.apache.commons.lang.StringUtils;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BaseDaoImpl<T> implements BaseDao<T> {
    @Resource(name = "sessionFactory")
    public SessionFactory sessionFactory;
    private final Class<T> entityClass;//具体的实现类
    private String identityName;//主键的名称

    public BaseDaoImpl() {
        //获取泛型化的父类
        ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
        //获取泛型运行期真实的类型
        this.entityClass = (Class<T>) type.getActualTypeArguments()[0];
    }

    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public BaseDaoImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    @PostConstruct
    public void init() {
        this.identityName = this.sessionFactory
                .getClassMetadata(this.entityClass).getIdentifierPropertyName();
    }

    public void save(T t) {
        this.getSession().save(t);
    }

    public void update(T t) {
        this.getSession().update(t);
    }

    public void delete(Serializable id) {
        T t = get(id);
        if (t != null) {
            this.getSession().delete(t);
        }
    }

    public T get(Serializable id) {
        return (T) this.getSession().get(entityClass, id);
    }

    public Long getMaxId() {
        ClassMetadata classMetadata = this.getSession()
                .getSessionFactory().getClassMetadata(entityClass);
        Long identity = (Long) this.getSession().createQuery("select count(" + classMetadata.getIdentifierPropertyName() + ") from " + entityClass.getName()).uniqueResult();
        if (identity == null) {
            return 1L;
        } else {
            return identity + 1;
        }
    }

    public List query(final String hql, final Object[] params, final int start, final int limit) {

        Query query = getSession().createQuery(hql);

        System.out.println(hql);

        //设置查询参数
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                query.setParameter(i, params[i]);
            }

        }
        //设置查询返回的起始行
        if (start > 0) {
            query.setFirstResult(start);
        }
        //设置查询返回结果的最大条数
        if (limit > 0) {
            query.setMaxResults(limit);
        }
        return query.list();


    }

    public List query(final String hql, final Object[] params) {
        return query(hql, params, -1, -1);
    }

    public List<T> queryEntity(String whereClause, Object[] params, int start, int limit) {
        StringBuffer hql = new StringBuffer("SELECT obj FROM " + entityClass.getName() + " obj WHERE 1=1 ");
        if (!whereClause.startsWith("ORDER BY")) {//如果不是以order by开始，则跟条件
            hql.append(" AND ").append(whereClause);
        } else {
            hql.append(" ").append(whereClause);//如果是以order by开始，则直接order by一个字段
        }
        return query(hql.toString(), params, start, limit);
    }

    public List<T> queryEntity(String condition, Object[] params) {
        return queryEntity(condition, params, -1, -1);
    }

    private int findCount(final BaseQuery baseQuery) {
        // select count(o) from Employee o where o.username like ? and o.email like ?
        final StringBuilder builder = new StringBuilder("select count(o) from " + entityClass.getName() + " o");
        String where = baseQuery.getWhere();
        // 有查询条件
        if (StringUtils.isNotBlank(where)) {
            builder.append(" where ").append(where);
        }
        System.out.println("PageResult findCount:" + builder.toString());

        Query query = getSession().createQuery(builder.toString());
        // 设置查询条件的值
        List params = baseQuery.getParams();
        int index = 0;
        for (Object object : params) {
            query.setParameter(index++, object);
        }
        return ((Long) query.uniqueResult()).intValue();

    }

    public PageResult<T> findPageResult(final BaseQuery baseQuery) {

        int count = findCount(baseQuery);
        if (count == 0) {
            return new PageResult<T>();
        }

        final PageResult<T> pageResult = new PageResult<T>(baseQuery.getCurrentPage(), baseQuery.getPageSize(), count);
        // select o from Employee o where o.username like ? and o.email like ?
        final StringBuilder builder = new StringBuilder("select o from " + entityClass.getName() + " o");
        String where = baseQuery.getWhere();
        // 有查询条件
        if (StringUtils.isNotBlank(where)) {
            builder.append(" where ").append(where);
        }
        System.out.println("PageResult findPageResult:" + builder.toString());


        Query query = getSession().createQuery(builder.toString());
        // 设置查询条件的值
        List params = baseQuery.getParams();
        // 索引jdbc:1,hibernate:0
        // for (int i = 0; i < params.size(); i++) {
        // query.setParameter(i, params.get(i));
        // }
        int index = 0;
        for (Object object : params) {
            query.setParameter(index++, object);
        }
        // 设置分页的信息
        // select o from Employee o limit 0,10
        // baseQuery里面的查询条件是有可能是有问题的
        // 必须使用做了错误处理后的pageResult
        int first = (pageResult.getCurrentPage() - 1) * pageResult.getPageSize();
        int max = pageResult.getPageSize();
        query.setFirstResult(first).setMaxResults(max);

        pageResult.setRows(query.list());
        return pageResult;
    }

    public Set<T> getEntrysByIds(Serializable[] ids) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("from " + this.entityClass.getName());
        buffer.append(" where " + this.identityName + " in(");
        for (int i = 0; i < ids.length; i++) {
            if (i == ids.length - 1) {
                buffer.append(ids[i]);
            } else {
                buffer.append(ids[i] + ",");
            }
        }
        buffer.append(")");
        return new HashSet<T>(this.getSession().createQuery(buffer.toString()).list());
    }

    public T queryEntryByProperty(final Map<String, Object> map) {
        final StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("from " + this.entityClass.getName());
        stringBuffer.append(" where 1=1");
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            stringBuffer.append(" and " + entry.getKey() + "=:" + entry.getKey());
        }

        Query query = getSession().createQuery(stringBuffer.toString());
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return (T) query.uniqueResult();

    }

    public List<T> queryEntrysByProperty(final Map<String, Object> map) {
        final StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("from " + this.entityClass.getName());
        stringBuffer.append(" where 1=1");
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            stringBuffer.append(" and " + entry.getKey() + "=:" + entry.getKey());
        }

        Query query = getSession().createQuery(stringBuffer.toString());
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return (List<T>) query.list();

    }
}
